package com.bestcem.xm.component.grpcmetrics.aspect;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.Timer;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.Duration;

@Aspect
public class GrpcMetricAspect {

    private MeterRegistry meterRegistry;

    @Autowired
    public void setMeterRegistry(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    //TODO 路径需要看下对不对

    /**
     * grpc service 拦截路径
     */
    @Pointcut("execution(* com.bestcem.xm.*.grpc.service.*(..))")
    public void servicePoint() {
    }

    //TODO 路径需要看下对不对

    /**
     * grpc client 拦截路径
     */
    @Pointcut("execution(* com.bestcem.xm.*.grpc.client.*(..))")
    public void clientPoint() {
    }

    /**
     * 拦截Service共有方法，上报接口执行情况到Prometheus
     */
    @Around("servicePoint()")
    public Object serviceExecute(ProceedingJoinPoint joinPoint) throws Throwable {
        String service = joinPoint.getTarget().getClass().getSimpleName();
        String method = joinPoint.getSignature().getName();
        Timer.Sample sample = Timer.start();
        boolean hasError = false;
        try {
            return joinPoint.proceed();
        } catch (Throwable e) {
            hasError = true;
            throw e;
        } finally {
            Timer timer = Timer.builder("timer_grpc_service_histogram")
                    .minimumExpectedValue(Duration.ofMillis(1))
                    .maximumExpectedValue(Duration.ofMinutes(3))
                    .sla(Duration.ofMillis(10), Duration.ofMillis(50), Duration.ofMillis(100), Duration.ofMillis(300), Duration.ofMillis(1000))
                    .tags(Tags.of("service", service, "method", method, "err", String.valueOf(hasError)))
                    .register(meterRegistry);
            sample.stop(timer);
        }
    }

    /**
     * 拦截client共有方法，上报接口执行情况到Prometheus
     */
    @Around("clientPoint()")
    public Object clientExecute(ProceedingJoinPoint joinPoint) throws Throwable {
        String service = joinPoint.getTarget().getClass().getSimpleName();
        String method = joinPoint.getSignature().getName();
        Timer.Sample sample = Timer.start();
        boolean hasError = false;
        try {
            return joinPoint.proceed();
        } catch (Throwable e) {
            hasError = true;
            throw e;
        } finally {
            Timer timer = Timer.builder("timer_grpc_client_histogram")
                    .minimumExpectedValue(Duration.ofMillis(1))
                    .maximumExpectedValue(Duration.ofMinutes(3))
                    .sla(Duration.ofMillis(10), Duration.ofMillis(50), Duration.ofMillis(100), Duration.ofMillis(300), Duration.ofMillis(1000))
                    .tags(Tags.of("service", service, "method", method, "err", String.valueOf(hasError)))
                    .register(meterRegistry);
            sample.stop(timer);
        }
    }
}